//
// Created by twetec on 25-7-30.
//

#include "handle_ssh_backup_task.h"

#include <libssh2.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <boost/algorithm/string/regex.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>

namespace network_prober::backup
{
// 过滤备份登录信息
static boost::regex s_backupResultLoginLineFilterRegxPattern{R"##(Last login:(.+)through ssh\.)##", boost::regex::icase};
// 备份信息More匹配
static boost::regex s_backupResultMoreSearchRegxPattern{R"##(([-]+)(\s*)More(\s*)[-]+)##", boost::regex::icase};

// static int s_waitSocket(int socket_fd, LIBSSH2_SESSION *session)
// {
//     struct timeval timeout;
//     int rc;
//     fd_set fd;
//     fd_set *writefd = NULL;
//     fd_set *readfd = NULL;
//     int dir;
//
//     timeout.tv_sec = 5;
//     timeout.tv_usec = 0;
//
//     FD_ZERO(&fd);
//     FD_SET(socket_fd, &fd);
//
//     /* now make sure we wait in the correct direction */
//     dir = libssh2_session_block_directions(session);
//
//
//     if (dir & LIBSSH2_SESSION_BLOCK_INBOUND)
//         readfd = &fd;
//
//     if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
//         writefd = &fd;
//
//     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
//
//     return rc;
// }

static int s_waitSocket(int socket_fd, LIBSSH2_SESSION *session)
{
    int epoll_fd, rc{0};
    struct epoll_event ev, events;
    int timeout_ms = 5000; // 5秒超时
    int dir = libssh2_session_block_directions(session);

    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        return -1;
    }

    // 设置要监听的事件
    ev.events = 0;
    ev.data.fd = socket_fd;

    // 读事件
    if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) {
        ev.events |= EPOLLIN;
    }
    // 写事件
    if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
        ev.events |= EPOLLOUT;
    }

    // 添加socket到epoll监听 管理红黑树上的文件描述符(添加，修改，删除等)
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
        close(epoll_fd);
        return -1;
    }

    // 等待事件（阻塞） 检测epoll树上，是否有就绪的文件描述符
    rc = epoll_wait(epoll_fd, &events, 1, timeout_ms);

    // 关闭epoll实例
    close(epoll_fd);

    return rc;
}

// libssh2初始化程序，只执行一次
static std::once_flag g_libssh2InitOnceFlag;

SSHBackupIPv4::SSHBackupIPv4(
    std::string_view interface,
    std::string_view target,
    std::string_view command,
    std::string_view account,
    std::string_view password,
    std::string_view privilegedPassword,
    std::uint32_t port
)
: m_interface(interface), m_target(target), m_command(command), m_account(account), m_password(password),
m_privilegedPassword(privilegedPassword), m_port(port)
{
    // 初始化libssh2库，在应用程序启动时，只调用一次
    std::call_once(g_libssh2InitOnceFlag, [] {
        // 初始化正常
        if (libssh2_init(0)) {
            SPDLOG_ERROR("libssh2库加载失败...");
            throw std::runtime_error("libssh2库加载失败...");
        }
    });
}

void SSHBackupIPv4::setOnBackupedCallback(std::function<void(std::string_view)> callback)
{
    m_onBackupedCallback = std::move(callback);
}

void SSHBackupIPv4::backup()
{
    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 发起探测
    m_onBackupedCallbackFuture = std::async(std::launch::async, [this, self] {
        // libssh执行结果
        int rc{0};

        // 创建socket(套接字) [AF_INET: IPv4, SOCK_STREAM: TCP]
        int socketfd = socket(AF_INET, SOCK_STREAM, 0);
        if (socketfd < 0) {
            // 输出日志
            SPDLOG_INFO("sockfd创建失败: {}", strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 设定本地网卡地址
        struct sockaddr_in interfaceAddr;
        memset(&interfaceAddr, 0, sizeof(interfaceAddr));
        interfaceAddr.sin_family = AF_INET;
        interfaceAddr.sin_port = htons(0);
        if (inet_pton(AF_INET, m_interface.c_str(), &interfaceAddr.sin_addr) <= 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 网口地址设置失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 绑定本机网口
        if (bind(socketfd, (sockaddr *)&interfaceAddr, sizeof(interfaceAddr)) < 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 网口地址绑定失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 设置目标地址
        struct sockaddr_in targetAddr;
        memset(&targetAddr, 0, sizeof(targetAddr));
        targetAddr.sin_family = AF_INET;
        targetAddr.sin_port = htons(m_port);
        if (inet_pton(AF_INET, m_target.c_str(), &targetAddr.sin_addr) <= 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 目标地址设置失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 连接目标地址
        if (connect(socketfd, (struct sockaddr *)&targetAddr, sizeof(targetAddr)) < 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("服务器连接失败: {}", strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 创建SSH会话
        LIBSSH2_SESSION* session = libssh2_session_init();
        if (!session) {
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - SSH会话创建失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 设置会话为非阻塞模式
        libssh2_session_set_blocking(session, 0);

        // SSH会话握手，握手没有结果时等待
        while ((rc = libssh2_session_handshake(session, socketfd)) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 握手有结果时，如果握手失败
        if (rc != 0) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 握手失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 握手成功后，进行帐号认证.未出结果时等待
        while ((rc = libssh2_userauth_password(session, m_account.c_str(), m_password.c_str())) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 认证出结果后，如果认证失败
        if (rc != 0) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 帐号密码认证失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 打开通道
        LIBSSH2_CHANNEL* channel = nullptr;
        // 如果通道打开中，则等待
        while ((channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 通道打开出结果后，如果通道打开失败
        if(!channel) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 通道打开失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 请求虚拟终端，未出结果时等待
        while ((rc = libssh2_channel_request_pty(channel, "xterm")) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 出结果后，如果请求失败
        if (rc != 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 虚拟终端请求失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 请求互动shell
        while ((rc = libssh2_channel_shell(channel)) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        if (rc != 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 互动shell创建失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 执行命令 命令末尾追加换行，让其可执行
        // std::string command = m_command + "\\n";

        while ((rc = libssh2_channel_write(channel, m_command.c_str(), strlen(m_command.c_str()))) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 如果执行命令失败
        if (rc <= 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 备份命令执行失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 读取命令执行的结果
        constexpr std::size_t BACKUP_DATA_SIZE = 50 * 1024;  // 备份数据区尺寸
        char backupData[BACKUP_DATA_SIZE];    // 备份数据区
        memset(backupData, 0, BACKUP_DATA_SIZE);  // 重置备份数据区

        char* backupDataPtr{backupData};    // 备份数据区指针
        std::size_t readRetryCount{0};  // 读取重试次数

        while (true) {
            // 判断重试次数是否超限(重试3次)，如果超限则停止读取，表示备份完毕
            if (readRetryCount >= 2) {
                // 向服务端写结束符
                while (libssh2_channel_send_eof(channel) == LIBSSH2_ERROR_EAGAIN) {
                    s_waitSocket(socketfd, session);
                }
                // 释放资源
                libssh2_channel_close(channel);
                libssh2_channel_free(channel);
                libssh2_session_free(session);
                LIBSSH2_SOCKET_CLOSE(socketfd);
                break;
            }

            // 通道读取缓存
            constexpr std::size_t CHANNEL_BUFFER_SIZE = 1024 * 10;   // 通道缓存区字节大小
            char channelBuffer[CHANNEL_BUFFER_SIZE];    // 通道缓存区
            memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);  // 重置通道缓存区

            // 已读到的字节数
            std::int32_t readBytesCount{0};

            do {
                // fprintf(stderr, "BackupData:\n");
                // for (std::size_t i = 0; i < 10240; ++i)
                //     fputc(backupData[i], stderr);
                // fprintf(stderr, "\n");

                // 处理完数据后，重置缓存
                memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);

                // 尝试读取数据
                readBytesCount = libssh2_channel_read(channel, channelBuffer, CHANNEL_BUFFER_SIZE);

                // 如果读取到了数据，则进行处理
                if (readBytesCount > 0) {
                    // 读到数据后，重置重试次数
                    readRetryCount = 0;

                    // 如果搜索到了more关键字
                    boost::smatch matches;
                    if (boost::regex_search(std::string{channelBuffer}, matches, s_backupResultMoreSearchRegxPattern, boost::format_first_only)) {
                        // 查看返回的字符串中，是否含有 More 符号
                        char* moreSymbolPtr = strstr(channelBuffer, matches[0].str().c_str());
                        // 如果存在more符号，则先过滤，再进行拷贝
                        if (moreSymbolPtr != NULL) {
                            // backupDataPtr永远指向下一个空的区域
                            memcpy(backupDataPtr, channelBuffer, moreSymbolPtr - channelBuffer);
                            // 移动备份数据指针到下一个空白区
                            backupDataPtr += (moreSymbolPtr - channelBuffer);

                            // 如果包含了more符号，则继续向服务端发送换行符，继续读取
                            std::int32_t moreBytesCount{0};
                            while ((moreBytesCount = libssh2_channel_write(channel, " ", strlen(" "))) == LIBSSH2_ERROR_EAGAIN) {
                                s_waitSocket(socketfd, session);
                            }
                            if (moreBytesCount < 0){
                                SPDLOG_INFO("向SSH服务端写入More指令失败..");
                            }

                            // 继续下一次读取
                            continue;
                        }
                    }

                    // 将读到的数据，存储到备份数据中
                    memcpy(backupDataPtr, channelBuffer, readBytesCount);
                    // 移动备份数据指针到下一个空白区
                    backupDataPtr += readBytesCount;
                }

                // 休息一会再读
                // std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
            while (readBytesCount > 0) ; // 如果这次读取到了数据，则继续下一次读取

            // 如果这次尝试读取失败，看是否是服务端还未响应完，没响应完则等待
            if (readBytesCount == LIBSSH2_ERROR_EAGAIN) {
                // 等待socket响应
                s_waitSocket(socketfd, session);
                // 如果服务器确认响应完了，读取确认就是失败的了，则记录重试次数
                readRetryCount ++;
            }
        }

        // 回调上报,设置备份内容
        std::string backupedData{backupData, static_cast<std::size_t>(backupDataPtr-backupData)};
        boost::algorithm::replace_regex(backupedData, s_backupResultLoginLineFilterRegxPattern, std::string{""}, boost::regex_constants::format_first_only);

        m_onBackupedCallback(backupedData);

        // 任务结束后，自动回收当前的self资源
    });
}

SSHBackupIPv4::~SSHBackupIPv4()
{

}

HandleSSHBackupIPv4Awaiter::HandleSSHBackupIPv4Awaiter(const database::BackupTaskModel &backupTask)
: m_interface(backupTask.interface), m_target(backupTask.address), m_command(backupTask.command),
m_account(backupTask.account), m_password(backupTask.password),
m_privilegedPassword(backupTask.privilegedPassword), m_port(backupTask.port)
{

}

bool HandleSSHBackupIPv4Awaiter::await_ready()
{
    return false;
}

void HandleSSHBackupIPv4Awaiter::await_suspend(std::coroutine_handle<> handle)
{
    // 保存协程控制对象
    m_coroutineHandle = handle;

    // 创建观测对象
    std::shared_ptr<SSHBackupIPv4> probePtr = std::make_shared<SSHBackupIPv4>(
        m_interface, m_target, m_command, m_account, m_password, m_privilegedPassword, m_port
    );

    // 设定观测结果回调
    probePtr->setOnBackupedCallback([this](std::string_view backupData) {
        // 保存观测延迟
        m_backupData = backupData;
        // 继续执行
        m_coroutineHandle.resume();
    });

    // 启动备份
    probePtr->backup();
}

std::string HandleSSHBackupIPv4Awaiter::await_resume()
{
    return m_backupData;
}


SSHBackupIPv6::SSHBackupIPv6(
    std::string_view interface,
    std::string_view target,
    std::string_view command,
    std::string_view account,
    std::string_view password,
    std::string_view privilegedPassword,
    std::uint32_t port
)
: m_interface(interface), m_target(target), m_command(command), m_account(account), m_password(password),
m_privilegedPassword(privilegedPassword), m_port(port)
{
    // 初始化libssh2库，在应用程序启动时，只调用一次
    std::call_once(g_libssh2InitOnceFlag, [] {
        // 初始化正常
        if (libssh2_init(0)) {
            SPDLOG_ERROR("libssh2库加载失败...");
            throw std::runtime_error("libssh2库加载失败...");
        }
    });
}

void SSHBackupIPv6::setOnBackupedCallback(std::function<void(std::string_view)> callback)
{
    m_onBackupedCallback = std::move(callback);
}

void SSHBackupIPv6::backup()
{
    // 指向当前对象的shared_ptr
    auto self{shared_from_this()};

    // 发起探测
    m_onBackupedCallbackFuture = std::async(std::launch::async, [this, self] {
        // libssh执行结果
        int rc{0};

        // 创建socket(套接字) [AF_INET: IPv4, SOCK_STREAM: TCP]
        int socketfd = socket(AF_INET6, SOCK_STREAM, 0);
        if (socketfd < 0) {
            // 输出日志
            SPDLOG_INFO("sockfd创建失败: {}", strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 设定本地网卡地址
        struct sockaddr_in6 interfaceAddr;
        memset(&interfaceAddr, 0, sizeof(interfaceAddr));
        interfaceAddr.sin6_family = AF_INET6;
        interfaceAddr.sin6_port = htons(0);
        if (inet_pton(AF_INET6, m_interface.c_str(), &interfaceAddr.sin6_addr) <= 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 网口地址设置失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 绑定本机网口
        if (bind(socketfd, (sockaddr *)&interfaceAddr, sizeof(interfaceAddr)) < 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 网口地址绑定失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 设置目标地址
        struct sockaddr_in6 targetAddr;
        memset(&targetAddr, 0, sizeof(targetAddr));
        targetAddr.sin6_family = AF_INET6;
        targetAddr.sin6_port = htons(m_port);
        if (inet_pton(AF_INET6, m_target.c_str(), &targetAddr.sin6_addr) <= 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 目标地址设置失败: {}", socketfd, strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 连接目标地址
        if (connect(socketfd, (struct sockaddr *)&targetAddr, sizeof(targetAddr)) < 0) {
            // 关闭socket
            close(socketfd);
            // 输出日志
            SPDLOG_INFO("服务器连接失败: {}", strerror(errno));
            // 回调上报
            m_onBackupedCallback("");
            // 停止执行
            return;
        }

        // 创建SSH会话
        LIBSSH2_SESSION* session = libssh2_session_init();
        if (!session) {
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - SSH会话创建失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 设置会话为非阻塞模式
        libssh2_session_set_blocking(session, 0);

        // SSH会话握手，握手没有结果时等待
        while ((rc = libssh2_session_handshake(session, socketfd)) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 握手有结果时，如果握手失败
        if (rc != 0) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 握手失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 握手成功后，进行帐号认证.未出结果时等待
        while ((rc = libssh2_userauth_password(session, m_account.c_str(), m_password.c_str())) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 认证出结果后，如果认证失败
        if (rc != 0) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 帐号密码认证失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 打开通道
        LIBSSH2_CHANNEL* channel = nullptr;
        // 如果通道打开中，则等待
        while ((channel = libssh2_channel_open_session(session)) == NULL && libssh2_session_last_error(session, NULL, NULL, 0) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 通道打开出结果后，如果通道打开失败
        if(!channel) {
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 通道打开失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 请求虚拟终端，未出结果时等待
        while ((rc = libssh2_channel_request_pty(channel, "xterm")) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 出结果后，如果请求失败
        if (rc != 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 虚拟终端请求失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 请求互动shell
        while ((rc = libssh2_channel_shell(channel)) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        if (rc != 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 互动shell创建失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 执行命令 命令末尾追加换行，让其可执行
        // std::string command = m_command + "\\n";

        while ((rc = libssh2_channel_write(channel, m_command.c_str(), strlen(m_command.c_str()))) == LIBSSH2_ERROR_EAGAIN) {
            s_waitSocket(socketfd, session);
        }
        // 如果执行命令失败
        if (rc <= 0) {
            // 关闭channel
            libssh2_channel_close(channel);
            // 释放channel
            libssh2_channel_free(channel);
            // 释放session
            libssh2_session_free(session);
            // 关闭socket
            LIBSSH2_SOCKET_CLOSE(socketfd);
            // 输出日志
            SPDLOG_INFO("sockfd: {} - 备份命令执行失败: {}", socketfd, strerror(errno));
            // 回调上报(备份失败则返回空字符串)
            m_onBackupedCallback("");
            // 结束执行
            return;
        }

        // 读取命令执行的结果
        constexpr std::size_t BACKUP_DATA_SIZE = 50 * 1024;  // 备份数据区尺寸
        char backupData[BACKUP_DATA_SIZE];    // 备份数据区
        memset(backupData, 0, BACKUP_DATA_SIZE);  // 重置备份数据区

        char* backupDataPtr{backupData};    // 备份数据区指针
        std::size_t readRetryCount{0};  // 读取重试次数

        while (true) {
            // 判断重试次数是否超限(重试3次)，如果超限则停止读取，表示备份完毕
            if (readRetryCount >= 2) {
                // 向服务端写结束符
                while (libssh2_channel_send_eof(channel) == LIBSSH2_ERROR_EAGAIN) {
                    s_waitSocket(socketfd, session);
                }
                // 释放资源
                libssh2_channel_close(channel);
                libssh2_channel_free(channel);
                libssh2_session_free(session);
                LIBSSH2_SOCKET_CLOSE(socketfd);
                break;
            }

            // 通道读取缓存
            constexpr std::size_t CHANNEL_BUFFER_SIZE = 1024 * 10;   // 通道缓存区字节大小
            char channelBuffer[CHANNEL_BUFFER_SIZE];    // 通道缓存区
            memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);  // 重置通道缓存区

            // 已读到的字节数
            std::int32_t readBytesCount{0};

            do {
                // fprintf(stderr, "BackupData:\n");
                // for (std::size_t i = 0; i < 10240; ++i)
                //     fputc(backupData[i], stderr);
                // fprintf(stderr, "\n");

                // 处理完数据后，重置缓存
                memset(channelBuffer, 0, CHANNEL_BUFFER_SIZE);

                // 尝试读取数据
                readBytesCount = libssh2_channel_read(channel, channelBuffer, CHANNEL_BUFFER_SIZE);

                // 如果读取到了数据，则进行处理
                if (readBytesCount > 0) {
                    // 读到数据后，重置重试次数
                    readRetryCount = 0;

                    // 如果搜索到了more关键字
                    boost::smatch matches;
                    if (boost::regex_search(std::string{channelBuffer}, matches, s_backupResultMoreSearchRegxPattern, boost::format_first_only)) {
                        // 查看返回的字符串中，是否含有 More 符号
                        char* moreSymbolPtr = strstr(channelBuffer, matches[0].str().c_str());
                        // 如果存在more符号，则先过滤，再进行拷贝
                        if (moreSymbolPtr != NULL) {
                            // backupDataPtr永远指向下一个空的区域
                            memcpy(backupDataPtr, channelBuffer, moreSymbolPtr - channelBuffer);
                            // 移动备份数据指针到下一个空白区
                            backupDataPtr += (moreSymbolPtr - channelBuffer);

                            // 如果包含了more符号，则继续向服务端发送换行符，继续读取
                            std::int32_t moreBytesCount{0};
                            while ((moreBytesCount = libssh2_channel_write(channel, " ", strlen(" "))) == LIBSSH2_ERROR_EAGAIN) {
                                s_waitSocket(socketfd, session);
                            }
                            if (moreBytesCount < 0){
                                SPDLOG_INFO("向SSH服务端写入More指令失败..");
                            }

                            // 继续下一次读取
                            continue;
                        }
                    }

                    // 将读到的数据，存储到备份数据中
                    memcpy(backupDataPtr, channelBuffer, readBytesCount);
                    // 移动备份数据指针到下一个空白区
                    backupDataPtr += readBytesCount;
                }

                // 休息一会再读
                // std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
            while (readBytesCount > 0) ; // 如果这次读取到了数据，则继续下一次读取

            // 如果这次尝试读取失败，看是否是服务端还未响应完，没响应完则等待
            if (readBytesCount == LIBSSH2_ERROR_EAGAIN) {
                // 等待socket响应
                s_waitSocket(socketfd, session);
                // 如果服务器确认响应完了，读取确认就是失败的了，则记录重试次数
                readRetryCount ++;
            }
        }

        // 回调上报,设置备份内容
        std::string backupedData{backupData, static_cast<std::size_t>(backupDataPtr-backupData)};
        boost::algorithm::replace_regex(backupedData, s_backupResultLoginLineFilterRegxPattern, std::string{""}, boost::regex_constants::format_first_only);

        m_onBackupedCallback(backupedData);

        // 任务结束后，自动回收当前的self资源
    });
}

SSHBackupIPv6::~SSHBackupIPv6()
{
}

HandleSSHBackupIPv6Awaiter::HandleSSHBackupIPv6Awaiter(const database::BackupTaskModel &backupTask)
: m_interface(backupTask.interface), m_target(backupTask.address), m_command(backupTask.command),
m_account(backupTask.account), m_password(backupTask.password),
m_privilegedPassword(backupTask.privilegedPassword), m_port(backupTask.port)
{

}

bool HandleSSHBackupIPv6Awaiter::await_ready()
{
    return false;
}

void HandleSSHBackupIPv6Awaiter::await_suspend(std::coroutine_handle<> handle)
{
    // 保存协程控制对象
    m_coroutineHandle = handle;

    // 创建观测对象
    std::shared_ptr<SSHBackupIPv6> probePtr = std::make_shared<SSHBackupIPv6>(
        m_interface, m_target, m_command, m_account, m_password, m_privilegedPassword, m_port
    );

    // 设定观测结果回调
    probePtr->setOnBackupedCallback([this](std::string_view backupData) {
        // 保存观测延迟
        m_backupData = backupData;
        // 继续执行
        m_coroutineHandle.resume();
    });

    // 启动备份
    probePtr->backup();
}

std::string HandleSSHBackupIPv6Awaiter::await_resume()
{
    return m_backupData;
}
}
